#include <ctype.h>
#include <string.h>

#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"

#include "7seg.h"
#include "globals.h"

static char disp_7seg_initialised = 0;
static alt_u8 value_7seg[36];

/* Initialise the lookup table for the 7-Seg display */
void init_7seg_display(void)
{
    if (!disp_7seg_initialised)
    {
        value_7seg[0]  = SEG7_ZERO;
        value_7seg[1]  = SEG7_ONE;
        value_7seg[2]  = SEG7_TWO;
        value_7seg[3]  = SEG7_THREE;
        value_7seg[4]  = SEG7_FOUR;
        value_7seg[5]  = SEG7_FIVE;
        value_7seg[6]  = SEG7_SIX;
        value_7seg[7]  = SEG7_SEVEN;
        value_7seg[8]  = SEG7_EIGHT;
        value_7seg[9]  = SEG7_NINE;
        
        value_7seg[10] = SEG7_A;
        value_7seg[11] = SEG7_B;
        value_7seg[12] = SEG7_C;
        value_7seg[13] = SEG7_D;
        value_7seg[14] = SEG7_E;
        value_7seg[15] = SEG7_F;
        value_7seg[16] = SEG7_G;
        value_7seg[17] = SEG7_H;
        value_7seg[18] = SEG7_I;
        value_7seg[19] = SEG7_J;
        value_7seg[20] = SEG7_K;
        value_7seg[21] = SEG7_L;
        value_7seg[22] = SEG7_M;
        value_7seg[23] = SEG7_N;
        value_7seg[24] = SEG7_O;
        value_7seg[25] = SEG7_P;
        value_7seg[26] = SEG7_Q;
        value_7seg[27] = SEG7_R;
        value_7seg[28] = SEG7_S;
        value_7seg[29] = SEG7_T;
        value_7seg[30] = SEG7_U;
        value_7seg[31] = SEG7_V;
        value_7seg[32] = SEG7_W;
        value_7seg[33] = SEG7_X;
        value_7seg[34] = SEG7_Y;
        value_7seg[35] = SEG7_Z;
        
        disp_7seg_initialised = 1;
    }
    
    return;
}

/* Delete all content on the 7-Segment display */
void Clear7Seg(void)
{
    const alt_u32 clear_bits = 0xFFFFFFFF;
    
    if (!disp_7seg_initialised)
    {
        init_7seg_display();
    }
    
    IOWR_ALTERA_AVALON_PIO_DATA(SEG7_BASE, clear_bits);
    
    return;
}

/* Write 4 character string to 7 seg */
void Write7Seg(const char * str)
{
    size_t length;
    char * output_text = (char *)str;
    alt_u32 output_bits = 0;
    int i;
    alt_u8 current_char, current_value;
    
    if (!disp_7seg_initialised)
    {
        init_7seg_display();
    }
    
    if (str == NULL)
    {
        return;
    }
    
    Clear7Seg();
    
    length = strlen(str);
    if (length > 4)
    {
        length = 4;
    }
    
    for (i = 0; i < length; i++)
    {
        current_char = (alt_u8)output_text[i];
        if (isdigit(current_char))
        {
            current_value = value_7seg[current_char - '0'];
        }
        else
        {
            current_char = toupper(current_char);
            if ((current_char >= 'A') && (current_char < 'Z'))
            {
                current_value = value_7seg[10 + current_char - 'A'];
            }
            else if (current_char == ' ')
            {
                current_value = 0xFF;
            }
            else
            {
               return;
            }
        }
        
        output_bits <<= 8;
        output_bits |= current_value;
    }
    
    /* Pad the rest with empty characters */
    if (length < 4)
    {
        for (i = length; i < 4; i++)
        {
            output_bits <<= 8;
            output_bits |= 0xFF;
        }
    }
    
    /* printf("Printing: %x\r\n", (int)output_bits); */
    IOWR_ALTERA_AVALON_PIO_DATA(SEG7_BASE, output_bits);
    
    return;
}
